import SearchForm from '@/components/searchform';
import {
  filterOrgAPI,
  filterOrgByAuthAPI,
  filterOtherOrgAPI,
  filterOtherOrgByAuthAPI,
  getOtherTreeOrgAPI,
} from '@/services/selectors';
import exporter from '@/utils/cache';
import {
  BLOCK_HEADER_HEIGHT,
  commonText,
  formatTreeData,
  isParamsEmpty,
  MODAL_FOOTER_HEIGHT,
  MODAL_HEADER_HEIGHT,
  MODAL_PADDING_HEIGHT,
} from '@/utils/utils';
import { Grid, Header } from 'gantd';
import { isEmpty, isEqual, get, cloneDeep } from 'lodash';
import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
import { connect } from 'umi';
import { cellComponents, columns, formSchema, searchUISchema, treeColumns } from './static';
import { getShowDataSource, recursionTreeData } from './utils';

const { selector: selectorCache }: { selector?: any } = exporter;

export interface Action {
  type: string;
  payload?: any;
}

const initalState = {
  filterData: [],
  filterInfo: {},
  filterLoading: false,
  pageInfo: { pageSize: 50, beginIndex: 0 },
  totalCount: 0,
};

function reducers(state: any, action: Action) {
  const { type, payload } = action;
  switch (type) {
    case 'save':
      return { ...state, ...payload };
    case 'reset':
      return { ...initalState };
  }
}

interface SelectorViewProps {
  multiple: boolean;
  excludeId?: string;
  modalHei?: number | undefined;
  onChange?: (selectedRowKeys: string[], selectedRows: object[]) => void;
  [propName: string]: any;
}

const SelectorView = React.forwardRef((props: SelectorViewProps, ref: any) => {
  const pageKey: string = 'groupSelectorView';
  const {
    currentUser,
    multiple,
    treeOrganizations,
    treeOrganizationsByAuth,
    excludeId,
    modalHei,
    tableHei,
    value,
    visible,
    selectedRowKeys,
    selectedRows,
    treeLoading,
    withAuth,
    dispatch,
    setSelectedItem,
    onChange,
    disabledByLevel = false,
  } = props;

  const [excludeData, setExcludeData] = useState([]);
  const [excludeLoading, setExcludeLoading] = useState(false);
  const [searchFormHei, setSearchFormHei] = useState(0);
  const [state, _dispatch] = useReducer(reducers, initalState);
  const { filterData, filterInfo, filterLoading, pageInfo, totalCount } = state;

  const initFetch = useCallback(() => {
    if (excludeId) return;
    // if (withAuth && treeOrganizationsByAuth.length || !withAuth && treeOrganizations.length) return;
    dispatch({ type: 'selectors/fetchTreeOrg', payload: { withAuth } });
  }, [treeOrganizations, excludeId, withAuth]);

  const handlerSelect = useCallback((_selectedRowKeys: any, _selectedRows: any) => {
    setSelectedItem(_selectedRowKeys, _selectedRows);
    onChange && onChange(_selectedRowKeys, _selectedRows);
  }, []);

  const getFilterData = useCallback(
    async (filterInfo, pageInfo) => {
      try {
        let api;
        if (excludeId) {
          api = withAuth ? filterOtherOrgByAuthAPI : filterOtherOrgAPI;
        } else {
          api = withAuth ? filterOrgByAuthAPI : filterOrgAPI;
        }
        _dispatch({ type: 'save', payload: { filterLoading: true } });
        const _filterInfo = excludeId ? { ...filterInfo, excludeId } : filterInfo;
        const res = await api({ data: { filterInfo: _filterInfo, pageInfo: pageInfo }, serviceId: 'fwSecurity' });
        const data = res.content || [];
        formatTreeData(data, 'children', { title: 'orgName' });
        _dispatch({
          type: 'save',
          payload: {
            filterData: data,
            filterInfo,
            pageInfo,
            totalCount: res.totalCount || 0,
            filterLoading: false,
          },
        });
      } catch (err) {
        console.error(err);
        _dispatch({ type: 'save', payload: { filterLoading: false } });
      }
    },
    [_dispatch, excludeId, withAuth],
  );

  const onPageChange = useCallback(
    (page = 0, pageSize = 50) => {
      getFilterData(filterInfo, { beginIndex: page, pageSize });
    },
    [filterInfo],
  );

  //smart高度改变
  const onSearchFormSizeChange = useCallback(
    ({ height, width }) => {
      setSearchFormHei(height);
    },
    [setSearchFormHei],
  );

  const resetState = useCallback(() => {
    !isEqual(initalState, state) && _dispatch({ type: 'reset' });
  }, [_dispatch, state]);

  const getExcludeData = useCallback(
    async (forceRender?: boolean) => {
      const key = `groupSelector_${withAuth ? 'auth' : 'all'}:${excludeId}`;
      let cacheData = selectorCache.get(key);
      if (!cacheData || forceRender) {
        try {
          setExcludeLoading(true);
          const res = await getOtherTreeOrgAPI({
            data: { id: excludeId, node: 'root', pageInfo: {} },
            serviceId: 'fwSecurity',
          });
          formatTreeData(res, 'children', { title: 'orgName' });
          selectorCache.set(key, res);
          cacheData = res;
          setExcludeLoading(false);
        } catch (err) {
          console.error(err);
          setExcludeLoading(false);
        }
      }
      setExcludeData(cacheData);
      resetState();
    },
    [excludeId, withAuth, resetState],
  );

  const handleSearch = useCallback(
    (params) => {
      if (isEmpty(params)) {
        excludeId
          ? getExcludeData(true)
          : dispatch({ type: 'selectors/fetchTreeOrg', payload: { withAuth }, cb: resetState });
      } else {
        getFilterData(params, pageInfo);
      }
    },
    [pageInfo, resetState, excludeId, withAuth, getFilterData],
  );

  const tableHeight = useMemo(() => {
    const diff =
      MODAL_HEADER_HEIGHT + MODAL_PADDING_HEIGHT * 2 + MODAL_FOOTER_HEIGHT + searchFormHei + BLOCK_HEADER_HEIGHT;
    if (!modalHei) return tableHei;
    const hei = modalHei - diff;
    return (hei > 0 && hei) || 'auto';
  }, [modalHei, tableHei, searchFormHei]);

  const realDataSource = useMemo(() => {
    if (!isEmpty(filterInfo)) return filterData;
    if (excludeId) return excludeData;
    return getShowDataSource((withAuth && treeOrganizationsByAuth) || treeOrganizations);
  }, [excludeId, withAuth, filterInfo, excludeData, treeOrganizations, treeOrganizationsByAuth, filterData]);

  const realDataSourceWithDisabled = useMemo(() => {
    const data = cloneDeep(realDataSource);
    if (disabledByLevel) {
      recursionTreeData(data);
    }

    return data;
  }, [realDataSource, disabledByLevel]);

  // 将数据平铺
  const flatDataSource = useMemo(() => {
    const res: any[] = [];
    function flat(arr: any[], res: any[]) {
      arr.forEach((item) => {
        const { children = [] } = item;
        res.push(item);
        if (children.length) flat(children, res);
      });
    }
    flat(realDataSource, res);
    return res;
  }, [realDataSource]);

  const withFilter = useMemo(() => {
    return !isParamsEmpty(filterInfo);
  }, [filterInfo]);

  useEffect(() => {
    excludeId && getExcludeData();
  }, [excludeId]);

  useEffect(() => {
    if (typeof visible === 'boolean') {
      visible && initFetch();
    }
  }, [visible]);

  useEffect(() => {
    if (visible) {
      if (Array.isArray(value) && value.length && flatDataSource.length > 0) {
        const selectedRow: any[] = [];
        value.forEach((id) => {
          const findItem = flatDataSource.find((item: any) => item.id === id);
          if (findItem) selectedRow.push(findItem);
        });
        setSelectedItem(value, selectedRow);
      }
    }

    return () => {
      setSelectedItem([], []);
    };
  }, [visible, value, flatDataSource]);

  const isRowSelectable = useCallback((rowNode) => {
    return !(get(rowNode, 'data.level') < 3);
  }, []);

  return (
    <>
      <SearchForm
        searchKey={`${pageKey}:${currentUser.id}`}
        schema={formSchema}
        uiSchema={searchUISchema}
        title={commonText.smartSearchTitleText}
        headerProps={{ type: 'line', bottomLine: false }}
        onSearch={handleSearch}
        onSizeChange={onSearchFormSizeChange}
        showBottomLine={false}
      />
      <Header title={commonText.smartGridTitleText} type="line" />
      {withFilter ? (
        <Grid
          hideMenuItemExport
          columns={columns}
          key="round"
          rowkey="id"
          dataSource={realDataSourceWithDisabled}
          loading={treeLoading || excludeLoading || filterLoading}
          height={tableHeight}
          rowSelection={{
            type: multiple ? 'multiple' : 'single',
            selectedKeys: selectedRowKeys,
            selectedRows,
            onSelect: handlerSelect,
          }}
          frameworkComponents={cellComponents}
          isRowSelectable={isRowSelectable}
          pagination={{
            total: totalCount, //总条数
            beginIndex: pageInfo.beginIndex, //当前页数
            pageSize: pageInfo.pageSize, //每页显示数
            onChange: onPageChange,
          }}
        />
      ) : (
        <Grid
          hideMenuItemExport
          columns={treeColumns}
          key="tree"
          rowkey="id"
          isCompute={true}
          dataSource={realDataSourceWithDisabled}
          loading={treeLoading || excludeLoading || filterLoading}
          height={tableHeight}
          treeData
          groupSuppressAutoColumn
          frameworkComponents={cellComponents}
          isRowSelectable={isRowSelectable}
          rowSelection={{
            type: multiple ? 'multiple' : 'single',
            selectedKeys: selectedRowKeys,
            selectedRows,
            onSelect: handlerSelect,
          }}
        />
      )}
    </>
  );
});

SelectorView.defaultProps = {
  multiple: false,
  tableHei: 'auto',
  value: [],
  withAuth: false,
};

export interface ConnectProps extends SelectorViewProps {
  viewRef: any;
}

class ConnectComp extends React.Component<ConnectProps> {
  state = {
    selectedRowKeys: [],
    selectedRows: [],
  };
  static defaultProps = {
    viewRef: {},
  };
  componentDidMount() {
    this.props.viewRef.current = this;
  }

  setSelectedItem = (selectedRowKeys: [string], selectedRows: [any]) => {
    this.setState({ selectedRowKeys, selectedRows });
  };
  getValues = () => {
    const { selectedRowKeys, selectedRows } = this.state;
    return { selectedRowKeys, selectedRows };
  };
  render() {
    const { selectedRowKeys, selectedRows } = this.state;
    return (
      <SelectorView
        {...this.props}
        selectedRowKeys={selectedRowKeys}
        selectedRows={selectedRows}
        setSelectedItem={this.setSelectedItem}
      />
    );
  }
}

export default connect(({ selectors, user, loading }: any) => ({
  currentUser: user.currentUser,
  treeLoading: loading.effects['selectors/fetchTreeOrg'],
  treeOrganizations: selectors.treeOrganizations,
  treeOrganizationsByAuth: selectors.treeOrganizationsByAuth,
}))(ConnectComp);
